TL;DR
현대 웹 개발 환경에서 Next.js는 단순한 프레임워크를 넘어 하나의 표준으로 자리매김했다. 뛰어난 성능과 우수한 개발자 경험을 제공하며 전 세계 수많은 개발자의 선택을 받고 있다. 이러한 성공의 중심에는 서버 사이드 렌더링(SSR), 정적 사이트 생성(SSG)과 같은 렌더링 최적화 기술과 더불어, 요청-응답 주기를 정교하게 제어할 수 있는 미들웨어(Middleware)와 같은 강력한 기능들이 있다. 개발자들은 이러한 도구들을 활용하여 빠르고 확장 가능하며 SEO에 친화적인 애플리케이션을 효율적으로 구축할 수 있었다.
그러나 기술의 발전은 언제나 양날의 검과 같다. 프레임워크의 뛰어난 장점은 생산성을 극대화하는 동시에, 그 내부 동작 원리에 대한 이해가 부족할 경우 예기치 못한 보안 위협의 단초를 제공하기도 한다. 본 리포트의 목적은 단순히 Next.js의 알려진 취약점을 나열하는 것을 넘어, 특정 1-day 취약점에 대한 심층 분석을 통해 그 근본 원인을 파악하고 실질적으로 안전한 개발 방향을 제시하는 데 있다.
Rewrite에서는 Next.js에서 발생하는 Cache Deception, SSRF, Middleware Bypass와 같은 CVE들을 확인하였고 이에 대해 깊게 공부해보고자 해당 CVE들에 대해 연구해보았다.
What is Next.js?
Next.js is a React framework for building full-stack web applications. You use React Components to build user interfaces, and Next.js for additional features and optimizations.
공식 문서의 설명에 따르면 Next.js는 “웹 애플리케이선 풀스택 개발을 위한 리액트 프레임워크”이다. React 라이브러리를 사용하여 사용자 인터페이스(UI)를 구축하고, Next.js를 통해 서버사이드 렌더링(SSR), 라우팅, API 구축과 같은 추가 기능 및 최적화를 구현한다.
Key Features of Next.js
1. Rendering Strategies
Next.js의 특징 중 가장 먼저 알아볼 것은 렌더링 전략이다. Next.js에서는 하나의 애플리케이션 안에서 페이지별로 다양한 렌더링 방식을 조합하여 사용할 수 있는 하이브리드 전략을 사용한다. 이를 통해 각 페이지의 특성에 맞는 렌더링 전략을 활용해 최적의 성능과 사용자 경험을 구현할 수 있다.
SSR (Server Side Rendering)
SSR은 사용자가 페이지를 요청할 때마다 서버에서 해당 페이지를 동적으로 생성하는 방식이다. 데이터가 자주 바뀌는 페이지에 적합하며, 항상 최신 데이터를 반영할 수 있기에 검색 엔진 최적화(SEO)에 유리하다. 하지만 매 요청마다 서버에서 렌더링이 이루어지므로 서버 부하가 발생할 수 있다.
1
2
3export async function getServerSideProps() {
return { props: { data: await fetchData() } };
}SSG (Static Site Generation)
SSG는 SSR과는 다르게 어플리케이션을 빌드할 때 HTML을 미리 생성하는 방식이다. 데이터가 바뀌지 않는 정적인 페이지를 CDN을 통해 즉시 제공하기 때문에 빠르지만, 데이터가 변경되면 어플리케이션 전체를 다시 빌드해야하는 단점이 있다.
1
2
3export async function getStaticProps() {
return { props: { data: await fetchData() } };
}ISR (Incremental Static Regeneration)
SSG의 단점을 보완한 방식으로, 빌드 시점에 페이지를 생성한 후 설정된 주기마다 백그라운드에서 페이지를 다시 생성하여 업데이트 하는 방식이다.
1
2
3
4
5
6export async function getStaticProps() {
return {
props: { data: await fetchData() },
revalidate: 60, // regenerate page every 60sec
};
}CSR (Client-Side Rendering)
클라이언트에서
fetch
또는axios
로 데이터를 요청한 후 받아와 HTML을 완성하는 방식이다.1
2
3
4"use client";
useEffect(() => {
fetch("/api/data").then(setData);
}, []);RSC (React Server Component)
RSC(React Server Component)는 컴포넌트를 서버에서 렌더링하는 기술이지만, 그 결과물을 클라이언트로 가져오는 과정은 데이터 통신 방식에 가깝다. 클라이언트는 전체 HTML이 아니라 그 조각에 가까운 RSC payload를 요청한다. 이 요청은 클라이언트fetch
요청 시Accept
헤더와 함께 이 헤더가 포함되며 서버는 바이너리 형식의 RSC 데이터를 반환하게 된다.1
2
3
4
5
6
7
8GET /dashboard?\_rsc=abc123 HTTP/1.1
Accept: text/x-component
RSC: 1
HTTP/1.1 200 OK
Content-Type: text/x-component
<RSC Payload>
2. Routing
Next.js의 라우팅 시스템은 파일 시스템을 기반으로 동작한다. 이는 폴더와 파일 구조를 만드는 것만으로 페이지 경로를 설정할 수 있게 하여, 복잡한 라우팅 라이브러리 설정의 필요성을 없애준다.
정적 라우팅
정적 라우팅은 이름이 고정된 URL 경로를 생성하는 방식이다. 폴더를 만들고 그 안에
page.js
파일을 생성하면 해당 폴더 이름이 그대로 URL 경로가 된다.1
2
3
4
5
6app/
├── about/
│ └── page.js ---> http://www.host.com/about
└── products/
└── all/
└── page.js ---> http://www.host.com/products/all동적 라우팅
URL의 일부가 변하는 페이지를 처리하는 방식이다. 폴더 이름에 대괄호[folderName]
를 사용한다.1
2
3
4app/
└── blog/
└── [slug]/
└── page.js ---> /blog/post1, /blog/post2 ...
Why Next.js?
Next.js는 다음과 같은 프로젝트에 특히 유용하다.
- 검색 엔진 최적화(SEO)가 중요한 웹사이트
- 고성능이 요구되는 플랫폼
- 복잡한 대시보드 및 웹 애플리케이션
CVE Analyze
1. CVE-2023-46298 (DoS via cache poisoning)
CVE-2023-46298은 SSR(Server Side Rendering) 페이지에서 발생하는 캐시 포이즈닝을 통한 서비스 거부(DoS) 취약점이다. 특수하게 조작된 프리페치(Prefetch) 요청을 보내 서버가 내용이 비어있는 응답을 반환하도록 유도할 수 있다. 이때 해당 응답에 Cache-Control
헤더가 존재하지 않아, CDN이 비어있는 응답을 캐싱하게 된다. 그 결과, 이후 동일한 페이지에 접근하는 모든 일반 사용자는 CDN으로부터 정상적인 데이터를 제공받지 못해 서비스를 이용할 수 없게 된다. CVE에 대한 기술적인 내용을 설명하기에 앞서 SSR과 prefetch에 대해 알아보자.
Part1. SSR, The Standard of Frontend
최근 프론트엔드 개발에서 빠질 수 없는 기술이 바로 SSR이다. HTML을 서버에서 생성하여 리턴하기 때문에 동적인 데이터를 반환하는 페이지에 적절한 기술이다. 하지만 매 요청 마다 HTML을 새로 렌더링하기 때문에 지연시간이 존재한다. 이를 해결하기 위해 prefetch
라는 기술이 존재한다.
prefetch
는 “클라이언트가 요청할 페이지의 데이터를 미리 다운로드 하는 기술”이다. 아래는 prefetch 기술의 예시이다.
1 | // index.tsx |
이 페이지에선 /ssr
경로로 이동할 수 있고, 해당 경로에서 렌더링 되는 페이지는 SSR이 적용된 페이지이다. 사용자가 index.tsx
페이지에 처음 접속하면 <Link>
컴포넌트가 화면에 렌더링 되고 Next.js는 /ssr
페이지에서 필요한 JSON 데이터를 미리 요청한다. (HTML 전체가 아닌 데이터만)
prefetch 요청
prefetch 요청 패킷 상세내용
localhost:3000
에 접근해 index.tsx
가 렌더링되면 /_next/data/<BUILD_ID>/ssr.json
으로 prefetch 요청이 발생하여 /ssr
에서 사용할 pageProps 데이터를 받아오는 것을 볼 수 있다.
Part2. Cache and CDN
CloudFront와 같은 CDN에서는 response 패킷의 cache-control
헤더가 존재하지 않으면 기본값(24시간)을 캐시 기간으로 사용하여 캐싱한다. 만약 위 prefetch 요청에서 Response 패킷에 cache-control
헤더가 없었다면, 각 CDN은 정해진 기간동안 같은 결과를 반환할 것이다. 그런데 만약 “빈 객체”를 반환하는 것으로 CDN에 캐싱된다면, 동일 URL을 사용하는 모든 사용자가 빈 값을 리턴받는 Cache Posining 취약점이 발생하고 이것이 CVE-2023-46298 의 발생 원인이다.
Cache Poisoning diagram
이제 cache-control
헤더가 없는 상황에서 빈 객체를 반환하게 할 수 있을지 알아보자.
Part3. Root Cause
1 | // https://github.com/vercel/next.js/blob/v13.4.19/packages/next/src/server/base-server.ts#L1487 |
renderToResponseWithComponentsImpl
은 SSR 요청을 처리하는 구현체이다. 만약 x-middleware-prefetch
헤더의 값이 1(true)일 경우 cache-control 헤더 없이 빈 객체가 반환된다. 만약 미들웨어가 존재하거나, 공격자가 악의적으로 헤더를 추가하여 요청한다면 CDN에 빈 객체가 캐싱되어 같은 URL에 접근하는 모든 사용자에게 빈 값을 리턴하여 서비스 거부(DoS) 공격이 성공하게 된다.
Part4. Proof of Concept
Normal Prefetch Request
일반적인 prefetch 요청에서는 cache-control
헤더와 리턴값이 함께 잘 반환되는 것을 볼 수 있다. CDN은 cache-control
헤더를 확인하여 캐싱 여부와 기간을 결정 할 것이다.
Bad Prefetch Request
같은 요청에 x-middleware-prefetch: 1
가 존재하면, cache-control
헤더 없이 빈 값이 반환된다. 이렇게 되면 CDN은 기본 캐싱 정책에 따라 일정 기간(Cloudfront의 경우 24시간) 동안 ssr.json
요청에 대해서는 빈 값을 반환하는 버그가 발생하게 된다.
NextJS-PoC/PoC-cve-2023-46298 at main · aest3ra/NextJS-PoC
Part5. Remediating and Defending
Diffing
Next.js 버전 13.4.20-canary.13에서 응답 헤더에 cache-control
헤더를 추가하여 Cache Poisoning을 방지하도록 수정되었다.
2. CVE-2025-29927 (Middleware Bypass)
CVE-2025-29927는 미들웨어의 무한 루프를 방지하기 위해 내부적으로 설계된 특별한 헤더인 x-middleware-subrequest
를 신뢰하여 공격자가 이 헤더를 조작하면 미들웨어 로직 전체를 우회할 수 있는 취약점이다.
Part1. Middleware of Next.js
Next.js의 미들웨어(Middleware)는 요청이 최종적으로 처리되기 전에 코드를 실행할 수 있게 해주는 기능이다. 다른 프레임워크 라이브러리를 사용해도 미들웨어를 구현할 수 있지만 Next.js에서는 src/middleware.js
에서 미들웨어를 쉽게 사용할 수 있다.
1 | // src/middleware.ts |
미들웨어는 보통 위 코드 샘플처럼, 인증 및 인가를 위해 사용한다. 그렇기에 미들웨어 자체를 건너뛸 수 있다면, 검증 로직들을 대부분 우회할 수 있게 된다.
Part2. Root Cause
1 | // https://github.com/vercel/next.js/blob/v15.2.2/packages/next/src/server/web/sandbox/sandbox.ts#L105 |
이 부분이 CVE-2025-29927
를 발생시키는 원인이 된다. 결론부터 말하자면 사용자의 요청이 아래 조건을 만족할 경우 미들웨어를 우회하는 것이 가능하다. 이를 위해 아래 조건이 성립되어야 한다.
x-middleware-subrequest
헤더와 함께 요청- 헤더 값을
:
기준으로 파싱한 배열의 길이가, 5 이상이 되어야 함 - 각 배열의 값이
params.name
값과 같아야 함.
조건을 만족시키 위해 withTaggedErrors
의 로직을 분석해보자.
요청 패킷에
x-middleware-subrequest
가 존재하면 그 값을 읽어:
기준으로 파싱하여subrequests
라는 변수에 저장한다. 아래의 예시를 보면 이해가 쉬울 것이다.1
2x-middleware-subrequest: aaa:bbb:ccc
subrequests -> ['aaa', 'bbb', 'ccc']subrequests
배열의 각 값과params.name
몇 개나 일치하는지 확인하고, 일치 하는 개수를depth
변수에 저장한다.params.name
은 미들웨어의 경로이고. Next.js 버전 13 이후로는middleware
또는src/middleware
둘 중에 하나가 된다.결국
params.name
값을 배열에 5개 이상 들어가도록 해야하는 것이기 때문에 최종 페이로드는 Next.js 버전 13 이상을 기준으로 다음과 같다.1
2
3
4
5
6GET /admin HTTP/1.1
x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
// if "middleware.js" or "middleware.ts" is in src/ folder
GET /admin HTTP/1.1
x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware
Part3. Proof of Concept
/admin
경로는 미들웨어의 인가 로직으로 보호되고 있어 적절한 권한 없이 요청을 보낼경우 /
경로로 리다이렉트 되는 것을 확인할 수 있다.
같은 경로에 x-middleware-subrequest
헤더와 그 값을 알맞게 추가하여, /admin
경로에 성공적으로 접근 한 것을 확인할 수 있다.
NextJS-PoC/PoC-cve-2025-29927 at main · aest3ra/NextJS-PoC
Part4. Remediating and Defending
서버 측에서 전역적으로 사용되는 x-middleware-subrequest-id
값을 생성하고 미들웨어 관련 헤더 검증 시 x-middleware-subrequest-id
와 x-middleware-subrequest
값을 함께 전달 받아 x-middleware-subrequest
헤더가 서버에서 생성된 것이 맞는지 검증하도록 패치되었다.
Update middleware request header (#77201) · vercel/next.js@52a078d
3. CVE-2024-46982 (Cache Poisoning)
CVE-2024-46982
는 HTTP 요청 내에 Next.js 서버에서 내부적으로 사용되는 헤더를 추가하여 정적 서버사이드 렌더링 엔드포인트의 캐시를 오염시킬 수 있는 취약점이다. 기본적으로 서버사이드 렌더링이 이루어지는 엔드포인트는 동적 / 정적 여부와 관계없이 캐시되지 않아야 한다. 그러나 해당 CVE의 영향을 받는 서버의 비동적 서버사이드 렌더링 엔드포인트에 특정 HTTP 헤더와 파라미터를 추가하여 요청을 전송할 경우, 서버의 응답에 Cache-Control: s-maxage=1, stale-while-revalidate
를 포함시키는 것이 가능하다. 즉 응답 캐싱을 강제할 수 있다는 의미이다. 그렇다면 Cache-Poisoning을 유도하기 위해 어떤 헤더를 추가해야 하며, 추가된 헤더가 Next.js 서버 내에서 어떤 식으로 파싱되었기에 취약점이 발생 했는지 알아보자.
Affected
- Next.js
>= 13.5.1
,< 14.2.10
- 동적(dynamic)이 아닌 SSR 경로를 사용하는 경우
1
pages/dashboard.tsx (vulnerable)
1
pages/blog/[slug].tsx (not vulnerable)
- 동적(dynamic)이 아닌 SSR 경로를 사용하는 경우
Part1. x-now-route-matches
Cache-Poisoning을 유도하기 위해 HTTP 요청에 추가되어야 하는 헤더는 다음과 같다.
1 | x-now-route-matches: 1 |
각 헤더의 역할을 설명하자면 다음과 같다.
먼저 x-now-route-matches
헤더는 Next.js 내부적으로 사용되는 헤더로, 현재 요청이 SSG
요청인지 판별하기 위해 사용되는 헤더이다. SSG
요청이란, 빌드 시 HTML 페이지 데이터를 미리 생성하여 빠른 응답과 캐싱을 위해 사용되는 기능이다.
1 | ... |
이는 Next.js가 요청 내에 x-now-route-matches
헤더가 있을 경우 해당 요청을 어떻게 처리 하는 지 알려주는 코드이다. 요청 내에 x-now-route-matches
헤더가 존재할 경우 isSSG
변수를 true
로 설정하여 해당 요청을 SSG
요청으로 인식하게 된다. Next.js는 요청을 SSG
요청으로 인식할 경우 다음과 같은 캐시 헤더를 설정하고 응답을 캐싱하도록 동작하게 된다.
1 | Cache-Control: s-maxage=N, stale-while-revalidate |
Part2. Root Cause
해당 CVE의 root cause는 base-server.ts
을 확인하여 쉽게 확인할 수 있다.
1 | if ( |
우선 첫번째로 요청에서 x-now-route-matches
헤더를 가져와 참조하는데 해당 헤더가 외부로부터 전달된 값인 지 내부적으로 생성된 값인지 검증하지 않는다.
1 | ... |
두번째로 코드에서 볼 수 있는 revalidate
값은 getStaticProps()
내부에서 사용되는 옵션으로, 최소한의 캐시 유효성을 보장하기 위한 캐싱 기간이다. Next.js의 코드를 확인해보면, revalidate
이 설정되어 있지 않을 경우 삼항 연산자를 통해 1 이라는 값을 설정하는 것을 확인할 수 있는데, revalidate
값이 1로 설정되면 해당 페이지는 1초가량 캐싱되므로 이로 인해 캐싱 관련 설정이 되어있지 않은 페이지도 캐싱되게 하는 것이 가능하다. 이렇게 2가지 요인으로 인해 취약점이 발생한다.
Part3. PoC for CVE-2024-46982
CVE-2024-46982
의 PoC는 굉장히 간단하다. 아래와 같이 HTTP 요청에 x-now-route-matches
헤더를 추가하는 것으로 취약점을 증명해낼 수 있다.
그러나 첨부된 사진의 Postman 요청을 보면 x-now-route-matches
헤더 이외에 X-Nextjs-Cache
헤더와 __nextDataReq
파라미터를 확인할 수 있다. 이는 취약점의 고도화를 위한 요소에 가깝다고 할 수 있다. 먼저 __nextDataReq
파라미터는 원래 해당 경로에서 리턴되어야 하는 HTML 요소가 아닌 pageProps
, __N_SSP
등 페이지 구성에 사용되는 요소를 요청하는 파라미터이다. 따라서 해당 파라미터와 함께 HTTP 요청을 전송하면 HTML 페이지가 아닌 페이지 구성에 사용되는 요소들만 리턴 받게 되는데, 이로 인해 DoS가 발생하게 된다(일반 이용자가 리턴 받아야하는 정상 페이지를 리턴받지 못하기 때문). 또한 X-Nextjs-Cache
는 쉽게 말해, 요청에 대해 어떤 캐싱 동작이 발생했는지 알려주는 헤더이다. PoC에서 설정된 값은 INVALIDATE
로, 이전에 저장된 캐시를 초기화 한다는 의미이다.
따라서 위 PoC를 해석하자면 다음과 같다.
x-now-route-matches:1
: 해당 요청은 SSG 요청이다.
__nextDataReq
: 페이지 구성 요소를 리턴해라.
X-Nextjs-Cache:INVALIDATE
: 캐시를 초기화 해라.
결과적으로 기존 캐시는 초기화 되며, 서버는 페이지 구성요소를 캐싱하여 모든 이용자에게 리턴하게 된다.
이때 서버 응답에 User-Agent
와 같은 클라이언트 입력 값이 포함되어 XSS 등의 취약점이 발생한다면 모든 이용자를 대상으로 한 공급망 공격 성격의 XSS 공격까지도 발생할 수 있다.
Part4. Remediating and Defending
https://github.com/vercel/next.js/commit/7ed7f125e07ef0517a331009ed7e32691ba403d3
패치는 다음과 같이 진행되었다. 기존에 개발자가 설정하지 않으면 자동으로 1로 설정되던 revalidate
값을 undefined
상태로 유지되도록 변경하였으며, 렌더링 시 revalidate
값이 설정되지 않았다면 명시적으로 값이 0이 되도록 로직을 변경하였다. 이러한 패치를 보고 “취약점의 근본 원인인 x-now-route-matches
헤더가 서버 내부 동작에 영향을 미치는 것을 직접 차단해야 하지 않는가?” 라는 의문이 생길 수 있는데, 충분히 타당한 의문이라고 생각한다. 하지만 Next.js 개발팀은 외부에서 전달 받은 x-now-route-matches
헤더가 내부적으로 영향을 미치지 않도록 패치하는 것보다 개발자가 따로 revalidate
값을 설정한 경로가 아닐 경우 캐싱이 이루어지지 않도록 패치하는 것을 선택했다. 이는 패치의 간결성과 다른 기능에 미칠 수 있는 영향 범위를 최소화하기 위한 결정일 것으로 추측된다.
4. CVE-2024-34351 (SSRF)
CVE-2024-34351
는 Host
헤더를 조작하고 Next.js에서만 사용되는 헤더를 추가하여 원하는 IP로 HTTP GET Request를 전송할 수 있는 SSRF 취약점이다. 일반적인 SSRF 취약점의 경우 서버에 “클라이언트가 조작 가능한 URL로 요청을 전송하는 코드”가 포함되어 발생하는 경우가 대다수인데, 해당 취약점의 경우에는 서버 측에 이런 로직이 없어도 발생할 수 있다. 심지어 HTTP 요청에 대한 응답까지도 확인할 수 있다. 아래는 해당 취약점에 대한 분석 내용이다.
Affected
- Next.js
>= 13.4.0
,< 14.1.1
- NextJS running with SELF-HOSTING
- NextJS application uses Server-Action
- Server-Action perform relative-Path Redirection
Part1. Next.js Server-Action
해당 CVE를 이해하기에 앞서 Next.js에서 사용되는 Server-Action
의 개념을 이해해야 한다. Server-Action
은 RSC
기반으로 App Router에서 사용할 수 있는 서버 함수 호출 방식이다.
1 | // app/page.tsx |
다음과 같은 코드가 있다고 가정한다. createPost()
는 서버 측에서 호출되는 함수임을 알 수 있는데, 위와 같이 로직을 설계하면 <form action={createPost}>
에서 {createPost}
부분에 서버 측 createPost()
함수를 식별 가능하게 하는 action ID 값이 들어가게 된다. 해당 폼이 제출됨으로써 서버에서는 action ID를 전달 받고 action ID에 매핑되는 서버 함수를 호출하게 되는 것이다.
Part2. Root Cause
위에서 설명한 Server-Action을 처리하는 과정에서 취약점이 발생했다. 다음 코드 로직을 통해 확인할 수 있다.
다음 코드는 Server-Action 호출 시 이를 핸들링하는 코드이다.
1 | ... |
코드 로직을 확인해보면 const host = originalHost.value
으로 Host
헤더를 참조하여 fetchUrl
을 생성하고, 해당 URL에 HEAD 요청을 전송한 뒤 응답 content-Type
이 RSC_CONTENT_TYPE_HEADER
(text/x-component
) 라면 GET 요청을 전송하는 것을 확인할 수 있다.
1 | export const RSC_CONTENT_TYPE_HEADER = "text/x-component" as const; |
또한 GET 요청 전송 이후 응답의 body를 참조하여 렌더링 결과를 생성하는 것을 확인할 수 있다. 이와 같은 로직으로 인해 해당 취약점이 발생했다.
Part3. PoC for CVE-2024-34351
root cause에서 알 수 있듯이, 취약점의 증명을 위해서 충족 되어야 하는, 또한 알아야 하는 조건은 다음과 같다.
Server-Action
의 사용 여부 및 Action ID(클라이언트 측에서 확인 가능한 값)HEAD
요청 시content-Type
으로text/x-component
를 반환하고GET
요청 시 요청자를 원하는 URL로 redirect 시키는 개인 서버
따라서 취약점의 재현을 위해선 아래와 같은 서버를 동작 시키고
1 | from flask import Flask, Response, request, redirect |
클라이언트 측에 노출된 Action ID를 찾아 서버 측에 다음과 같이 요청을 전송하면 된다.
1 | POST / HTTP/1.1 |
이를 통해 취약점을 재현할 수 있다.
Part4. Remediating and Defending
https://github.com/vercel/next.js/commit/8f7a6ca7d21a97bc9f7a1bbe10427b5ad74b9085
패치는 다음과 같이 진행되었다.
액션 핸들링 로직과 서버 시작 시 로직이 수정되었다. 우선 취약점이 발생했던 액션 핸들링 로직에서 originalHost.value
보다 process.env.__NEXT_PRIVATE_HOST
값을 우선적으로 참조하도록 변경 되었으며, 서버 시작 시 process.env.__NEXT_PRIVATE_HOST
를 설정하는 로직을 추가하여 특별한 상황이 아니라면 클라이언트로부터 전달 받은 헤더를 참조하여 요청을 전송하지 않도록 하였다. 변경 사항으로 봐선 환경 변수가 수정되거나 prototype Pollution 등의 공격을 통해 process.env
를 조작할 수 있는 경우 SSRF가 다시 가능할 것으로 보인다.
Conclusion
Next.JS 리서치를 통해 다른 웹 프레임워크와 차별화되는 고유한 기능들을 많이 확인할 수 있었다. 이러한 특징들은 사용자 편의성을 높이고 서버 성능을 향상시키는 분명한 장점을 가지고 있다. 하지만 위에서 소개한 대부분의 CVE가 그렇듯이 헤더에 대한 관리 부재로 인해 다양한 취약점이 발생한다. 이러한 CVE들을 통해 Next.js가 앞으로 더욱 발전하며 새로운 기능을 추가할 때 외부 입력 값을 신뢰하지 않고 검증하는 보안적 관점을 함께 고려하여 더욱 완성도 높고 안전한 프레임워크를 만들 것을 기대한다.
References
https://zhero-web-sec.github.io/research-and-things/nextjs-cache-and-chains-the-stale-elixir
https://zhero-web-sec.github.io/research-and-things/nextjs-and-the-corrupt-middleware